package com.kalua.list.harvester.parser;

import java.util.Collections;
import java.util.Set;
import java.util.concurrent.locks.ReadWriteLock;
import java.util.concurrent.locks.ReentrantReadWriteLock;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

import com.google.common.collect.Sets;
import com.obixlabs.commons.util.LockUtil;

public abstract class AbstractContentLinkExtractor implements ContentLinkExtractor{
		
	protected static final String DEFAULT_HTML_REGEX_PATTERN = 
			"\\b(https?|ftp|file)://[-a-zA-Z0-9+&@#/%?=~_|!:,.;]*[-a-zA-Z0-9+&@#/%=~_|]";
	
	protected static final String DEFAULT_EXCLUSION_PATTERN = 
			".*(\\.(css|js|bmp|gif|jpe?g|png|tiff?|mid|mp2|mp3|mp4|wav|avi|mov|mpeg|ram|m4v|pdf" 
				+ "|rm|smil|wmv|swf|wma|zip|rar|gz|zones|specialoffers|SpecialOffers|dialogues|anonymous|promoType))$";
		
	private Pattern linkPattern;
	private Pattern exclusionPattern;
	private Pattern pageTitlePattern;

	private ReadWriteLock readWriteLock;	
		
	protected AbstractContentLinkExtractor( ) 
	{ this(DEFAULT_HTML_REGEX_PATTERN); }
	
	protected AbstractContentLinkExtractor(	String linkRegex) 
	{ this(linkRegex, DEFAULT_EXCLUSION_PATTERN); }
	
	protected AbstractContentLinkExtractor(	String linkRegex,
																	String exclusionRegex) 
	{ this(Pattern.compile(linkRegex), Pattern.compile(exclusionRegex)); }
	
	
	protected AbstractContentLinkExtractor(	Pattern linkPattern,
																	Pattern exclusionPattern) {
		super();
		this.readWriteLock = new ReentrantReadWriteLock();
		this.linkPattern = linkPattern;
		this.exclusionPattern = exclusionPattern;
		this.pageTitlePattern = Pattern.compile("<title>(.*?)</title>");
	}	

	protected String getPageTitle(String content) {
		String result;
		Matcher matcher = this.pageTitlePattern.matcher(content);
		if (matcher.find()) {
			result = matcher.group();
			int substringIndex =result.indexOf(">") + 1;
			int endIndex = result.lastIndexOf("<");
			result = result.substring(substringIndex, endIndex);
		} else result = null;
		return result;
	}
	
	protected Set<String> getOutgoingLinks(Pattern pattern, String content) {
		Set<String> result = Sets.newHashSet();
		
		Matcher matcher = pattern.matcher(content);
		String candidateLink;
		while (matcher.find()) {
			candidateLink=matcher.group();
			candidateLink = candidateLink.trim();
			if (!isExcluded(candidateLink))
				result.add(candidateLink);
		}		
		return result;
	}
	
	protected Set<String> getOutgoingLinks(String content) 
	{ return getOutgoingLinks(this.linkPattern, content); }

	protected Pattern getLinkPattern() { return this.linkPattern; }	
	protected Pattern getExclusionPattern() { return this.exclusionPattern; }
	
	protected boolean isExcluded(String candidateLink) 
	{ return this.exclusionPattern.matcher(candidateLink).matches(); }

	protected Set<String> getReadOnlyCopy(Set<String> field) {
		Set<String> result;
		LockUtil.acquireReadLock(this.readWriteLock);
		try {
			if (field == null)
				result = Collections.unmodifiableSet(Sets.newHashSetWithExpectedSize(1));
			else result = Collections.unmodifiableSet(field);
		} finally {
			LockUtil.releaseReadLock(this.readWriteLock);
		}
		return result;
	}
	
	protected ReadWriteLock getReadWriteLock() { return this.readWriteLock; }	
}